﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using Xoohoo.Infrastructure.FastReflectionLib;
using System.Globalization;

namespace Xoohoo.Html
{
    public static class TextAreaExtensions
    {
        #region Static Constructor

        private const int TextAreaRows = 2;
        private const int TextAreaColumns = 20;
        private static Dictionary<string, object> implicitRowsAndColumns = new Dictionary<string, object> {
            { "rows", TextAreaRows.ToString(CultureInfo.InvariantCulture) },
            { "cols", TextAreaColumns.ToString(CultureInfo.InvariantCulture) },
        };

        private static IMethodInvoker s_TextAreaHelperInvoker;
        static TextAreaExtensions()
        {
            MethodInfo textAreaHelperMethodInfo = typeof(System.Web.Mvc.Html.TextAreaExtensions).GetMethod("TextAreaHelper", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            s_TextAreaHelperInvoker = new MethodInvoker(textAreaHelperMethodInfo);
        }

        #endregion

        #region TextArea

        public static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model
            , Expression<Func<TModel, TProperty>> expression)
        {
            return htmlHelper.TextAreaFor(model, expression, null);
        }
        public static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model
            , Expression<Func<TModel, TProperty>> expression
            , object htmlAttributes)
        {
            return htmlHelper.TextAreaFor(model, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }
        public static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model, Expression<Func<TModel, TProperty>> expression
            , IDictionary<string, object> htmlAttributes)
        {
            return htmlHelper.TextAreaFor(model, expression, implicitRowsAndColumns, htmlAttributes);
        }
        public static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model, Expression<Func<TModel, TProperty>> expression
            , int rows
            , int columns
            , object htmlAttributes)
        {
            return htmlHelper.TextAreaFor(model, expression, GetRowsAndColumnsDictionary(rows, columns), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }
        public static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model, Expression<Func<TModel, TProperty>> expression
            , int rows
            , int columns
            , IDictionary<string, object> htmlAttributes)
        {
            return htmlHelper.TextAreaFor(model, expression, GetRowsAndColumnsDictionary(rows, columns), htmlAttributes);
        }
        private static MvcHtmlString TextAreaFor<TViewModel, TModel, TProperty>(this HtmlHelper<TViewModel> htmlHelper
            , TModel model
            , Expression<Func<TModel, TProperty>> expression
            , IDictionary<string, object> rowsAndColumns
            , IDictionary<string, object> htmlAttributes)
        {
            ViewDataDictionary<TModel> viewData = new ViewDataDictionary<TModel>(model);
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, viewData);

            return (MvcHtmlString)s_TextAreaHelperInvoker.Invoke(
                null
                , htmlHelper
                , metadata
                , ExpressionHelper.GetExpressionText(expression)
                , rowsAndColumns
                , htmlAttributes);

        }

        private static Dictionary<string, object> GetRowsAndColumnsDictionary(int rows, int columns)
        {
            if (rows < 0)
            {
                throw new ArgumentOutOfRangeException("rows");
            }
            if (columns < 0)
            {
                throw new ArgumentOutOfRangeException("columns");
            }
            Dictionary<string, object> dictionary = new Dictionary<string, object>();
            if (rows > 0)
            {
                dictionary.Add("rows", rows.ToString(CultureInfo.InvariantCulture));
            }
            if (columns > 0)
            {
                dictionary.Add("cols", columns.ToString(CultureInfo.InvariantCulture));
            }
            return dictionary;
        }

        #endregion

    }
}
